import os,sys,os.path
if __name__ == "__main__":         
   lucid_base_path = os.path.normpath(os.path.join(os.path.dirname(__file__),"..","..",".."))
   sys.path.insert(0,lucid_base_path)

from PyQt4 import QtGui, QtCore
import lucid.core
import osg2
import qt_editor_base
from pydispatch import dispatcher

class ShaderEditor(object):
   """ Helper class for setting up and controlling editor for shaders. """
   def __init__(self):
      self.editWidget = QtShaderEditor(self)
      text_widget = self.editWidget.textEdit
      
      self.editWidget.connect(self.editWidget.mActionApply, 
                              QtCore.SIGNAL("triggered()"), self.onApply)
      save_action = QtGui.QAction("Save",text_widget)
      save_action.setShortcut("Ctrl+S")
      text_widget.connect(save_action, QtCore.SIGNAL("triggered()"), self.onApply)      
      text_widget.addAction(save_action)
      
      self.mGetter = None
      self.mSetter = None
   
   def open(self, chunkObj, propName, getter, setter):
      self.mChunk = chunkObj
      self.mPropName = propName
      self.mGetter = getter
      self.mSetter = setter

      # Get the contents
      shader_text = self.mGetter()
      self.editWidget.textEdit.setPlainText(shader_text)

      # Show the widget
      self.editWidget.show()

   def onApply(self):
      new_shader_text = str(self.editWidget.textEdit.toPlainText())
      self.mSetter(new_shader_text)
      dispatcher.send(lucid.core.signal.SelectedFieldContainerModified)
      

class QtShaderEditor(QtGui.QMainWindow, qt_editor_base.Ui_MainWindow):
   """ Simple container widget. """
   def __init__(self, editorObj, parent=None):
      QtGui.QMainWindow.__init__(self, parent)
      self.editorObj = editorObj
      self.setupUi()
      self.setupHighlighter()

   def setupUi(self):
      """ Local UI setup support. """
      qt_editor_base.Ui_MainWindow.setupUi(self,self)
      self.textEdit.setAcceptRichText(False)
      

   def closeEvent(self, event):
      """ Apply the shader on close. """
      self.editorObj.onApply()      
      event.accept()

   def setupHighlighter(self):
      self.highlighter = Highlighter()
      
      glsl_identifiers = ["float","vec2","vec3","vec4","int","ivec2","ivec3","ivec4",
                          "bool","bvec2","bvec3","bvec4","mat2","mat3","mat4",
                          "void","sampler1D","sampler2D","sampler3D","samplerCube",
                          "sampler1DShadow","sampler2DShadow"]
      glsl_identifier_match = "\\b" + "|".join(glsl_identifiers) + "\\b"
      
      idFormat = QtGui.QTextCharFormat()
      #idFormat.setFontWeight(QtGui.QFont.Bold)
      idFormat.setForeground(QtCore.Qt.blue)
      self.highlighter.addMapping(glsl_identifier_match, idFormat)
      
      comment_format = QtGui.QTextCharFormat()
      #singleLineCommentFormat.setForeground(QtGui.QColor("#77ff77"))
      comment_format.setForeground(QtCore.Qt.darkGreen)
      self.highlighter.addMapping("(//[^\n]*)|(/\\*.*\\*/)", comment_format)
      
      #quotationFormat = QtGui.QTextCharFormat()
      #quotationFormat.setBackground(QtCore.Qt.cyan)
      #quotationFormat.setForeground(QtCore.Qt.blue)
      #self.highlighter.addMapping("\".*\"", quotationFormat)
      
      functionFormat = QtGui.QTextCharFormat()
      functionFormat.setFontWeight(QtGui.QFont.Bold)
      #functionFormat.setForeground(QtCore.Qt.blue)
      #self.highlighter.addMapping("\\b[a-z0-9_]+\\(.*\\)", functionFormat)
      self.highlighter.addMapping("\\b\w+\\(", functionFormat)
      
      font = QtGui.QFont()
      font.setFamily("Monospace")
      font.setFixedPitch(True)
      font.setPointSize(9)
      
      self.textEdit.setFont(font)
      self.highlighter.addToDocument(self.textEdit.document())


class Highlighter(QtCore.QObject):
    def __init__(self, parent=None):
        QtCore.QObject.__init__(self, parent)
        
        self.mappings = {}
        
    def addToDocument(self, doc):
        self.connect(doc, QtCore.SIGNAL("contentsChange(int, int, int)"), self.highlight)
    
    def addMapping(self, pattern, format):
        self.mappings[pattern] = format
    
    def highlight(self, position, removed, added):
        doc = self.sender()
    
        block = doc.findBlock(position)
        if not block.isValid():
            return
    
        endBlock = QtGui.QTextBlock()
        if added > removed:
            endBlock = doc.findBlock(position + added)
        else:
            endBlock = block
    
        while block.isValid() and not (endBlock < block):
            self.highlightBlock(block)
            block = block.next()
    
    def highlightBlock(self, block):
        layout = block.layout()
        text = block.text()
    
        overrides = []
    
        for pattern in self.mappings:
            expression = QtCore.QRegExp(pattern)
            i = text.indexOf(expression)
            while i >= 0:
                range = QtGui.QTextLayout.FormatRange()
                range.start = i
                range.length = expression.matchedLength()
                range.format = self.mappings[pattern]
                overrides.append(range)
    
                i = text.indexOf(expression, i + expression.matchedLength())
    
        layout.setAdditionalFormats(overrides)
        block.document().markContentsDirty(block.position(), block.length())

def debug_print(text):
   print "----- Text -------\n", text

def debug_get():
   text = """
// This is the test file
uniform vec3 myVar
uniform vec2 var
attribute vec4
int ivec2 ivec3 ivec4
bool bvec2 bvec3 bvec4 
mat2 mat3 mat4
void
sampler1D sampler2D sampler3D
samplerCube
sampler1DShadow sampler2DShadow

/* this si a multiline
comment.
*/

/*  Single line */

const float var = 10;
varying vec4 var_var;

vec4 method(in val, out val, inout val)
{

}


main()
{

   vec.yxz
   vec.rga
   vec.stp
   
}
"""
   return text


if __name__ == "__main__":
   app = QtGui.QApplication(sys.argv)
   se = ShaderEditor()
   se.open(None,"empty", debug_get, debug_print)      
   sys.exit(app.exec_())

